package com.gs.cd.utils;

//auth: seven
//
//date: 2020/12/22 17:48:06

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.gs.cd.model.resource.SysResource;
import lombok.Data;
import lombok.NonNull;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 树转换工具
 * todo 排序问题
 */
public class TreeUtils {
    /*测试*/
    public static void test() {
        SysResource f1 = new SysResource();
        f1.setId("f1");
        SysResource f2 = new SysResource();
        f2.setId("f2");
        SysResource c1 = new SysResource();
        c1.setId("c1");
        c1.setParentId("f1");
        SysResource c2 = new SysResource();
        c2.setId("c2");
        c2.setParentId("f2");
        SysResource cc2 = new SysResource();
        cc2.setId("cc2");
        cc2.setParentId("c2");
        ArrayList<SysResource> list = new ArrayList<>();
        list.add(f1);
        list.add(f2);
        list.add(c1);
        list.add(c2);
        list.add(cc2);
        Collection<TreeBean<SysResource>> treeBeans = list2Tree(list, "id", "parentId");
        Collection<SysResource> sysResources = tree2List(treeBeans);
        System.out.println(JSON.toJSONString(sysResources));
    }


    /**
     * @param treeList        树集合
     * @param fatherFieldName 父亲字段
     * @param childFiledName  子字段
     * @param <T>
     * @return
     */
    public static <T> Collection<TreeBean<T>> list2Tree(@NonNull Collection<T> treeList,
                                                        @NonNull String fatherFieldName,
                                                        @NonNull String childFiledName) {
        if (treeList.isEmpty()) {
            return new ArrayList<>();
        }
        Field father = null;
        Field child = null;
        //获取 父属性信息 子属性信息
        for (T t : treeList) {
            Class<?> aClass = t.getClass();
            //获取父亲字段
            try {
                father = aClass.getDeclaredField(fatherFieldName);
                //获取子字段
                child = aClass.getDeclaredField(childFiledName);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
            break;
        }
        ArrayList<TreeBean<T>> treeBeans = new ArrayList<>();
        Field finalFather = father;
        Field finalChild = child;
        //对象转换为treeBean
        treeList.forEach(t -> {
            try {
                Object f = invokeGetByField(t, finalFather);
                Object c = invokeGetByField(t, finalChild);
                treeBeans.add(new TreeBean<>(t, f, c));
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        });
        //根据parentId group
        Map<Object, List<TreeBean<T>>> collect = treeBeans.stream().collect(Collectors.groupingBy(TreeBean::getParentId));
        //添加child
        treeBeans.forEach(tTreeBean -> tTreeBean.setChild(collect.get(tTreeBean.getId())));
        //只获取father节点
        return treeBeans.stream().filter(v -> "null".equals(v.getParentId())).collect(Collectors.toList());
    }


    /**
     * 树转换 list
     *
     * @param list
     * @param <T>
     * @return
     */
    public static <T> Collection<T> tree2List(@NonNull Collection<TreeBean<T>> list) {
        if (list.isEmpty()) return new ArrayList<>();
        ArrayList<T> re = new ArrayList<>();
        list.forEach(tTreeBean -> {
            re.add(tTreeBean.getT());
            if (tTreeBean.getChild() != null) {
                Collection<T> ts1 = tree2List(tTreeBean.getChild());
                re.addAll(ts1);
            }
            tTreeBean.setChild(null);
        });
        return re;
    }

    /**
     * 执行属性的get方法
     *
     * @param t
     * @param field
     * @param <T>
     * @return
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException    todo 静态的怎么搞？？
     */
    private static <T> Object invokeGetByField(T t, Field field) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        if (Modifier.isStatic(field.getModifiers())) return null;
        return t.getClass().getMethod("get" + StrUtil.upperFirst(field.getName())).invoke(t);
    }

}


@Data
class TreeBean<T> {
    private T t;
    @JsonIgnore
    private Object id;
    @JsonIgnore
    private Object parentId;

    public TreeBean() {
    }

    public TreeBean(T t, Object id, Object parentId) {
        if (parentId == null) {
            this.parentId = "null";
        } else {
            this.parentId = parentId;
        }
        this.t = t;
        this.id = id;
    }

    private List<TreeBean<T>> child = new ArrayList<>();
}
